﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BesAsm.Stormwater.TimeSeries
{
  public class TimeSeries<T> : IDictionary<DateTime, T>
  {
    public string Name { get; set; }
    private DateTime _startDate;
    public DateTime StartDate
    {
      get
      {
        if (_isDirty)
          Clean();
        return _startDate;
      }
    }
    private DateTime _endDate;
    public DateTime EndDate
    {
      get
      {
        if (_isDirty)
          Clean();
        return _endDate;
      }
    }
    private bool _isEquidistant;
    public bool IsEquidistant
    {
      get
      {
        if (_isDirty)
          Clean();
        return _isEquidistant;
      }
    }
    private TimeSpan? _interval;
    public TimeSpan? Interval
    {
      get
      {
        if (_isDirty)
          Clean();
        return _interval;
      }
    }

    private void Clean()
    {      
      if (_dictionary.Count == 0)
        return;

      _startDate = _dictionary.Keys.First();
      _endDate = _dictionary.Keys.Last();

      DateTime dt1 = _dictionary.Keys.ElementAt(1);

      TimeSpan? interval1 = dt1 - _startDate;
      TimeSpan? interval2;

      _isEquidistant = true;
      foreach (DateTime dt2 in _dictionary.Keys.Skip(2))
      {
        interval2 = interval1;
        interval1 = dt2 - dt1;

        if (interval2 != interval1)
        {
          _isEquidistant = false;
          break;
        }

        dt1 = dt2;
      }

      _interval = _isEquidistant ? interval1 : null;
      _isDirty = false;
    }
    private bool _isDirty = true;

    private IDictionary<DateTime, T> _dictionary = new SortedDictionary<DateTime, T>();

    public IDictionary<DateTime, T> GetData()
    {
      return _dictionary;
    }

    public void SetData(IDictionary<DateTime, T> dictionary)
    {
      _isDirty = true;
      _dictionary = dictionary;
    }

    public T this[int index]
    {
      get { return _dictionary.ElementAt(index).Value; }
      set { _dictionary[_dictionary.ElementAt(index).Key] = value; }
    }

    #region IDictionary<DateTime,T> Members

    public void Add(DateTime key, T value)
    {
      _isDirty = true;
      _dictionary.Add(key, value);
    }

    public bool ContainsKey(DateTime key)
    {
      return _dictionary.ContainsKey(key);
    }

    public ICollection<DateTime> Keys
    {
      get { return _dictionary.Keys; }
    }

    public bool Remove(DateTime key)
    {
      _isDirty = true;
      return _dictionary.Remove(key);
    }

    public bool TryGetValue(DateTime key, out T value)
    {
      _isDirty = true;
      return _dictionary.TryGetValue(key, out value);
    }

    public ICollection<T> Values
    {
      get { return _dictionary.Values; }
    }

    public T this[DateTime key]
    {
      get
      {
        return _dictionary[key];
      }
      set
      {
        _isDirty = true;
        _dictionary[key] = value;
      }
    }

    #endregion

    #region ICollection<KeyValuePair<DateTime,T>> Members

    public void Add(KeyValuePair<DateTime, T> item)
    {
      _isDirty = true;
      ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).Add(item);
    }

    public void Clear()
    {
      _isDirty = true;
      ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).Clear();
    }

    public bool Contains(KeyValuePair<DateTime, T> item)
    {
      return ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).Contains(item);
    }

    public void CopyTo(KeyValuePair<DateTime, T>[] array, int arrayIndex)
    {
      ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).CopyTo(array, arrayIndex);
    }

    public int Count
    {
      get { return ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).Count; }
    }

    public bool IsReadOnly
    {
      get { return ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).IsReadOnly; }
    }

    public bool Remove(KeyValuePair<DateTime, T> item)
    {
      _isDirty = true;
      return ((ICollection<KeyValuePair<DateTime, T>>)_dictionary).Remove(item);
    }

    #endregion

    #region IEnumerable<KeyValuePair<DateTime,T>> Members

    public IEnumerator<KeyValuePair<DateTime, T>> GetEnumerator()
    {
      return _dictionary.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return _dictionary.GetEnumerator();
    }

    #endregion
  }
}
